#pragma once

#include "evt_loop.h"
#include "ssl_util.h"
#include "tcp_acceptor.h"
#include "tcp_conn.h"
#include "time_wheel.h"
#include "timer.h"

namespace qio {

class TcpServer final {
 public:
  struct Config final {
    IPAddress address{"0.0.0.0", 0};  // Address
    bool reuse_port{true};            // SO_REUSE_PORT
    bool reuse_addr{true};            // SO_REUSE_ADDR
    Backlog backlog{128};             // backlog
    std::size_t buffer_size{1024 * 1024 * 4};  // 连接每次读取数据的 buffer 大小
    std::shared_ptr<SSLHelper> ssl_helper{nullptr};  // SSL 上下文
    TimeoutMs rd_timeout{60 * 1000};                 // 读超时时间
    TcpAcceptor::UniqueBufferGenerator buffer_generator{
        nullptr};  // buffer 生成器,如果为 nullptr ,则使用默认的 ChanBuffer
  };

 public:
  TcpServer(EventLoop *loop, const Config &conf) QIO_NOEXCEPT;

  ~TcpServer() QIO_NOEXCEPT;

  DISABLE_CPY_MOV(TcpServer)

  void Start() QIO_NOEXCEPT;

  void Stop() QIO_NOEXCEPT;

  inline EventLoop *GetLoop() const QIO_NOEXCEPT { return loop_; }

  inline const Config &GetServerConfig() const QIO_NOEXCEPT {
    return server_config_;
  }

  inline void OnEstablished(TcpConn::OnEstablishedCallback &&cb) QIO_NOEXCEPT {
    conn_establish_cb_ = std::forward<TcpConn::OnEstablishedCallback>(cb);
  }

  inline void OnDisconnected(TcpConn::OnDisconnectedCallback &&cb)
      QIO_NOEXCEPT {
    conn_disconn_cb_ = std::forward<TcpConn::OnDisconnectedCallback>(cb);
  }

  inline void OnMessage(TcpConn::OnMessageCallback &&cb) QIO_NOEXCEPT {
    conn_msg_cb_ = std::forward<TcpConn::OnMessageCallback>(cb);
  }

  inline char *GetReadBuffer() const QIO_NOEXCEPT { return conn_read_buffer_; }

  inline std::size_t GetReadBufferLength() const QIO_NOEXCEPT {
    return conn_read_buffer_len_;
  }

 private:
  void HandleAcceptorError(TcpAcceptor *) QIO_NOEXCEPT;

  void HandleServerClosed(TcpAcceptor *) QIO_NOEXCEPT;

  SharedTimeoutHandle GenerateTimeoutHandle(const SharedTcpConn &conn)
      QIO_NOEXCEPT;

  UniqueBuffer GenerateUniqueBuffer() const QIO_NOEXCEPT;

 private:
  EventLoop *loop_;
  TcpAcceptor *acceptor_;
  Config server_config_;
  std::size_t conn_read_buffer_len_;
  char *conn_read_buffer_;
  TcpConn::OnEstablishedCallback conn_establish_cb_;
  TcpConn::OnDisconnectedCallback conn_disconn_cb_;
  TcpConn::OnMessageCallback conn_msg_cb_;
  TimeWheel time_wheel_;
};

using TcpServerConfig = TcpServer::Config;

}  // namespace qio
